<?php
/*********************************************
  Dragonfly CMS, Copyright (c) 2004 by DragonflyCMS Dev. Team.
  http://dragonflycms.org

  Dragonfly is released under the terms and conditions
  of the GNU GPL version 2 or any later version
**********************************************/

class Installer_Module extends Installer
{

	public $error;

	protected $module;
	protected $id;
	protected $name;
	protected $path;

	public function __construct($name, $bypass=false)
	{
		if (!preg_match('#^[a-z0-9_\-]+$#i', $name)) {
			$this->error = 'Module name characters error.';
			return;
		}
		$this->path = MODULE_PATH.$name.'/install/';
		if (is_file($this->path .'cpg_inst.php')) {
			require($this->path .'cpg_inst.php');
			if (!class_exists($name)) {
				$this->error = 'Mismatch between module name and installer class name.';
				return;
			}
		} else {
			$this->error = 'Module installer is missing.';
			return;
		}
		parent::__construct($bypass ?: isset($this->module->bypass) && $this->module->bypass);
		$this->name = $name;
		$this->module = new $name();
		if (!$this->test && isset($this->module->test)) { $this->test = $this->module->test; }
		return true;
	}

	public function add_module()
	{
		$db = Dragonfly::getKernel()->SQL;
		try {
			$db->begin();
			$this->module->pre_install() && $this->module->exec();
			$db->commit();

			if (!$this->repair()) return;

			//$db->begin();
			$this->id = $db->insert('modules', array('title'=>$this->name, 'uninstall'=>1, 'version'=>$this->module->version), 'mid');
			$this->sync_config() || $this->sync_radmin() || $this->sync_blocks() || $this->sync_userconfig();
			$this->exec() && $this->module->post_install() && $this->module->exec();
			//$db->commit();
		} catch (\Poodle\SQL\Exception $e) {
			$this->error = $e->__tostring();
			$this->rollback();
			$this->module->rollback();
			$db->query("DELETE FROM ".$db->TBL->modules." WHERE title='{$this->name}'");
			return;
		}
		return true;
	}

	public function upgrade_module($prev_version)
	{
		$db = Dragonfly::getKernel()->SQL;
		try {
			$db->begin();
			$this->module->pre_upgrade($prev_version) && $this->module->exec();
			$db->commit();

			if (!$this->repair()) return;

			$db->begin();
			$this->sync_config() || $this->sync_radmin() || $this->sync_userconfig();
			$this->exec() && $this->module->post_upgrade($prev_version) && $this->module->exec();
			$db->query("UPDATE {$db->TBL->modules} SET version='{$this->module->version}' WHERE title='{$this->name}'");
			$db->commit();
		} catch (\Poodle\SQL\Exception $e) {
			$this->error = $e->__tostring();
			$this->rollback();
			$this->module->rollback();
			$db->query("UPDATE {$db->TBL->modules} SET version='{$prev_version}' WHERE title='{$this->name}'");
			return;
		}
		return true;
	}

	public function remove_module()
	{
		global $CPG_SESS;
		$db = Dragonfly::getKernel()->SQL;
		$CPG_SESS['admin']['uninstall'] = '';
		unset($CPG_SESS['admin']['uninstall']);
		try {
			$db->begin();
			$this->module->pre_uninstall() && $this->module->exec();
			foreach ($this->module->dbtables as $table) {
				$this->add_query('DROP', $table);
			}
			if ($this->module->config) {
				$this->add_query('DELETE', 'config_custom', "cfg_name='".strtolower($this->name)."'");
			}
			if ($this->module->radmin) {
				$this->drop_radmin('radmin'.strtolower($this->name));
			}
			$this->exec();
			if ($this->id = $db->sql_fetchrow($db->sql_query("SELECT mid FROM {$db->TBL->modules} WHERE title='{$this->name}'"))) {
				$this->id = $this->id[0];
				$db->query("DELETE FROM {$db->TBL->blocks_custom} WHERE mid=".$this->id);
			}
			$db->query("DELETE FROM {$db->TBL->modules} WHERE title='{$this->name}'");
			$db->commit();
			$this->module->post_uninstall() && $this->module->exec();
			$db->optimize($db->TBL->modules);
			if ($this->module->config) { $db->optimize($db->TBL->config_custom); }
			if ($this->module->blocks) { $db->optimize($db->TBL->blocks_custom); }
		} catch (\Poodle\SQL\Exception $e) {
			$this->error = $e->__tostring();
			$this->rollback();
			$this->module->rollback();
			$this->rollback();
			return;
		}
		return true;
	}

	public function repair()
	{
		$db = Dragonfly::getKernel()->SQL;
		if (is_file($this->path .'schema.xml') && !$this->sync_from_file('schema')) {
			return;
		}

		if (is_file($this->path .'data.xml') && !$this->sync_from_file('data')) {
			return;
		}
		return true;
	}

	protected function sync_from_file($file)
	{
		$db = Dragonfly::getKernel()->SQL;
		if ($db->XML->syncSchemaFromFile($this->path .$file .'.xml')) {
			try {
				$db->begin();
				foreach ($db->XML->queries as $query) {
					try {
						$db->query($query);
					} catch (\Poodle\SQL\Exception $e) {
						$this->error = $e;
						return false;
					}
				}
				$db->commit();
				return true;
			}
			catch (\Poodle\SQL\Exception $e) {
				$this->error = $e;
				return false;
			}
		} else {
			$this->error = '<pre>'.print_r($db->XML->errors, true).'</pre>';
			return false;
		}
	}

	public function sync_config() {
		global $prefix;
		$db = Dragonfly::getKernel()->SQL;
		if (!empty($this->module->config) && is_array($this->module->config)) {
			$sql = array();
			foreach ($this->module->config as $field => $value) {
				if (preg_match('#^[a-z0-9_\-]+$#i', $field)) {
					$sql[] = "('{$this->name}', '{$field}', ".$db->quote($value).")";
				}
			}
			$this->add_query(
				'INSERT_MULTIPLE',
				'config_custom',
				array (
					'cfg_name, cfg_field, cfg_value',
					implode(',', $sql)
				),
				"cfg_name='{$this->name}'"
			);
		}
	}

	public function sync_radmin() {
		$radmin = strtolower($this->name);
		if (!empty($this->module->radmin) && !isset($_SESSION['DF_VISITOR']->admin->radmin[$radmin])) {
			$this->add_radmin('radmin' .$radmin);
		} elseif (empty($this->module->radmin) && isset($_SESSION['DF_VISITOR']->admin->radmin[$radmin])) {
			$this->drop_radmin('radmin' .$radmin);
		}
	}

	private function add_radmin($radmin)
	{
		$this->add_query('ADD', 'admins', array($radmin, 'INT1(1)', false, 0));
	}

	private function drop_radmin($radmin)
	{
		$this->add_query('DEL', 'admins', $radmin, array($radmin, 'INT1(1)', false, 0));
	}

	public function sync_blocks() {
		$db = Dragonfly::getKernel()->SQL;
		if (!empty($this->module->blocks)) {
			$result = $db->query('SELECT bid, bposition FROM '.$db->TBL->blocks.' WHERE active=1');
			if ($result->num_rows) {
				$in_modules = array();
				$l = $c = $r = $d = 1;
				while ($row = $result->fetch_row()) {
					$in_modules[] = "({$row[0]}, {$this->id}, '{$row[1]}', ".$$row[1].")";
					++$$row[1];
				}
				$this->add_query(
					'INSERT_MULTIPLE',
					'blocks_custom',
					array (
						'bid, mid, side, weight',
						implode(',', $in_modules)
					),
					'mid='.$this->id
					);
			}
			$result->free();
		}
	}

	public function sync_userconfig() {
		if (!empty($this->module->userconfig) && is_array($this->module->userconfig)) {}
	}

	public function __get($key)
	{
		$allowed = array('radmin', 'version', 'name', 'description', 'author', 'website');
		if (in_array($key, $allowed)) { return $this->$key; }

	}
}
